package dict;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

import db.Controller;


public class Dictionary {
	public boolean boolAvailable = false;// decide if idr object has loaded the
	// entries
	private int delCount = 0;
	private String strURL = null;// path to the .dict , .ifo, .idx files
	private IfoFile ifoFile = null;
	private IdxFile idxFile = null; // idr stores a list of entries
	private DictFile dictFile = null;

	public int getDelCount() {
		return delCount;
	}

	public void setDelCount(int delCount) {
		this.delCount = delCount;
	}

	public String getStrURL() {
		return strURL;
	}

	public void setStrURL(String strURL) {
		this.strURL = strURL;
	}

	public IfoFile getIfoFile() {
		return ifoFile;
	}

	public void setIfoFile(IfoFile ifoFile) {
		this.ifoFile = ifoFile;
	}

	public IdxFile getIdxFile() {
		return idxFile;
	}

	public void setIdxFile(IdxFile idxFile) {
		this.idxFile = idxFile;
	}

	public DictFile getDictFile() {
		return dictFile;
	}

	public void setDictFile(DictFile dictFile) {
		this.dictFile = dictFile;
	}

	/**
	 * Constructor
	 * 
	 * @param url
	 *            dictionary's url
	 * @param del
	 *            delCount
	 */
	public Dictionary(String url, int del) {
		this.delCount = del;
		this.strURL = url;
		this.ifoFile = new IfoFile(strURL + ".ifo");
		this.idxFile = new IdxFile(strURL + ".idx", ifoFile.getLongWordCount(),
				ifoFile.getLongIdxFileSize());
		this.dictFile = new DictFile(strURL + ".dict");
		if (this.ifoFile.boolIsLoaded && this.idxFile.boolIsLoaded) {
			this.boolAvailable = true;
		}
	}

	/**
	 * reload dictionary
	 */
	public void reLoad() {
		this.boolAvailable = false;
		this.ifoFile.reload();
		this.idxFile.reload();
		if (this.ifoFile.boolIsLoaded && this.idxFile.boolIsLoaded) {
			this.boolAvailable = true;
		}
	}

	/**
	 * lookup a word by its index
	 * 
	 * @param idx
	 *            word's index
	 * @return word's meaning if found,otherwise error message
	 */
	public String lookupWord(int idx) {
		if (idx < 0 || idx >= idxFile.getLongWordCount()) {
			return "not found";
		}
		WordEntry tempEntry = idxFile.entryList.get((int) idx);
		return dictFile.getWordData(tempEntry.longOffset, tempEntry.longSize);
	}

	/**
	 * lookup a word
	 * 
	 * @param word
	 *            word's name
	 * @return word's meaning if found,otherwise error message
	 */
	public String lookupWord(String word) {
		if (!boolAvailable) {
			return "the dictionary is not available";
		}
		int idx = (int) idxFile.findIndexForWord(word);
		return lookupWord(idx);
	}
	

	/**
	 * @param word
	 * @return
	 */
	public List<Word> getNNearestWords(String word) {
		if (boolAvailable) {
			int idx = (int) idxFile.findIndexForWord(word);
			int nMax = Controller.getNumOfNearestWords() + idx;
			List<Word> wordList = new ArrayList<Word>();

			if (nMax > idxFile.getLongWordCount()) {
				nMax = (int) idxFile.getLongWordCount();
			}

			for (int i = idx; i < nMax; i++) {
				if (i != 0) {
					Word tempWord = new Word();
					tempWord.strWord = idxFile.entryList.get(i).strWord;
					tempWord.index = i;
					wordList.add(tempWord);
				}
			}
			return wordList;
		}
		return null;
	}

	/**
	 * check if a word is in dictionary
	 * 
	 * @param word
	 *            word's name
	 * @return true if found,false if not
	 */
	public boolean existWord(String word) {
		int wordIndex = (int) idxFile.findIndexForWord(word);
		String lwrWord = word.toLowerCase();

		if (wordIndex >= idxFile.getLongWordCount())
			return false;

		if (lwrWord.equals(idxFile.entryList.get(wordIndex).strLwrWord)) {
			return true;
		}
		return false;
	}

	/**
	 * @param pWord
	 *            words list
	 * @param pMean
	 *            meanings list
	 * @return true if successful,false if fail
	 */
	public boolean addListOfWords(String pWord[], String pMean[]) {
		if (pWord.length != pMean.length || pWord.length == 0)
			return false;
		try {
			for (int i = 0; i < pWord.length; i++) {
				String strLwrWord = pWord[i].toLowerCase();
				int pos = (int) idxFile.findIndexForWord(strLwrWord);
				boolean bExist = false;
				long nextOffset = dictFile.addData(pMean[i]);

				if (pos < (int) idxFile.getLongWordCount()) {
					if (strLwrWord.compareTo(((WordEntry) idxFile.entryList
							.get(pos)).strLwrWord) == 0) {
						bExist = true;
					}
				}

				if (nextOffset >= 0) {
					if (bExist == false) {
						idxFile.addEntry(pWord[i], nextOffset, pMean[i]
								.length(), pos);
					} else {
						WordEntry tempEntry = idxFile.entryList.get(pos);
						tempEntry.longOffset = nextOffset;
						tempEntry.longSize = pMean[i].length();
					}
				}
			}
			idxFile.write();
			ifoFile.setLongIdxFileSize(idxFile.getLongIdxFileSize());
			ifoFile.setLongWordCount(idxFile.getLongWordCount());
			ifoFile.write();
		} catch (Exception ex) {
			return false;
		}
		return true;
	}

	/**
	 * Add a word with its meaning
	 * 
	 * @param word
	 * @param meaning
	 * @return true if successful,false if fail
	 */
	public boolean addWord(String word, String meaning) {
		String[] pWord = new String[1];
		String[] pMean = new String[1];
		pWord[0] = word;
		pMean[0] = meaning;
		return addListOfWords(pWord, pMean);
	}

	/**
	 * @param pWord
	 *            words list
	 * @return true if successful,false if fail
	 */
	public boolean removeListOfWords(String pWord[]) {
		int delNum = 0;

		for (int i = 0; i < pWord.length; i++) {
			if (idxFile.removeEntry(pWord[i])) {
				delNum++;
			}
		}
		if (delNum > 0) {
			delCount += delNum;
			idxFile.write();
			ifoFile.setLongIdxFileSize(idxFile.getLongIdxFileSize());
			ifoFile.setLongWordCount(idxFile.getLongWordCount());
			ifoFile.write();
			return true;
		}
		return false;
	}

	/**
	 * @param word
	 * @return
	 */
	public boolean removeWord(String word) {
		String[] pWord = new String[1];
		pWord[0] = word;
		return removeListOfWords(pWord);
	}

	/**
	 * @return
	 */
	public boolean reorganize() {
		String strTempURL = strURL + ".temp";
		boolAvailable = false;
		try {
			DataOutputStream dto = new DataOutputStream(new FileOutputStream(
					strTempURL));
			long offset = 0;

			for (int i = 0; i < idxFile.getLongWordCount(); i++) {
				DataInputStream dti = new DataInputStream(new FileInputStream(
						dictFile.getStrFileName()));
				WordEntry etr = (WordEntry) idxFile.entryList.get(i);
				byte[] bt = new byte[(int) etr.longSize];
				dti.skip(etr.longOffset);
				dti.read(bt);
				dti.close();
				dto.write(bt);
				dto.flush();
				etr.longOffset = offset;
				offset += bt.length;
				idxFile.entryList.set(i, etr);
			}
			dto.close();

			if (idxFile.write()) {
				(new File(dictFile.getStrFileName())).delete();
				new File(strTempURL).renameTo(new File(dictFile
						.getStrFileName()));
				boolAvailable = true;
			}
			delCount = 0;
		} catch (Exception ex) {
		}
		return boolAvailable;
	}
}
